/********************************************************************************
 * Copyright : LiuYao
 * Author : LiuYao
 * Date : 2017-11-24
 * Description : implement the autodiff
********************************************************************************/
#include <iostream>
#include <typeinfo>
#include <random>
#include "../include/mytensorflow.h"
#include "../session/session.h"

using namespace std;
using namespace mytensorflow;

void logistic_regression_v2_test(){
    int sample_num = 4;
    Matrix w_mat(3, 1, 1);
    w_mat[0][0] = 1;
    w_mat[1][0] = 4;
    w_mat[2][0] = 0.2;
    auto y = placeholder(Shape(sample_num, 1));
    auto x = placeholder(Shape(sample_num, 3));
    auto w = variable(w_mat);
    auto activation = sigmoid(matmul(x, w));
    //auto loss = sum(-log(pow(activation, y) * pow(1 - activation, 1 - y) + 1e-6));
    auto lhs = y * log(activation + 1e-16);
    auto rhs = (1 - y) * log(1 - activation + 1e-16);
    auto add = lhs + rhs;
    //auto add = y * log(activation + 1e-16) + (1 - y) * log(1 - activation + 1e-16);
    auto neg_ones = constant(Matrix(sample_num, 1, -1));
    auto multi = multiply(neg_ones, add);
    auto loss = sum(multi);
    auto optimizer = gradient_descent_optimizer(loss, 0.01);
//    cout << "activation : " << activation.getNode() << endl;
//    cout << "add_lhs : " << lhs.getNode() << endl; 
//    cout << "add_rhs : " << rhs.getNode() << endl; 
//    cout << "add : " << add.getNode() << endl;
//    cout << "neg_ones : " << neg_ones.getNode() << endl;
//    cout << "multi : " << multi.getNode() << endl;
//    cout << "loss : " << loss.getNode() << endl;
    unordered_map<Node*, Matrix> map;
    Matrix x_mat = readDigitalCSV("/home/LiuYao/Documents/mytensorflow/test_data/x_test.csv");
    Matrix y_mat = readDigitalCSV("/home/LiuYao/Documents/mytensorflow/test_data/y_test.csv");
    map[x.getNode()] = x_mat;
    map[y.getNode()] = y_mat;
    Session sess;
    for(int i = 0; i < 10000; i++){
        sess.run(optimizer, map);
        cout << "loss : " << sess.run(loss, map) << endl;
        cout << "activation : " << sess.run(activation, map) << endl;
        cout << "================================================================================" << endl;
    }
}

void neural_network_test(){
    int sample_num = 20000;
    auto y = placeholder(Shape(sample_num, 1));
    auto x = placeholder(Shape(sample_num, 3));
    auto w1 = variable(random_matrix(3, 8));
    auto a1 = sigmoid(matmul(x, w1));
    auto w2 = variable(random_matrix(8, 1));
    auto a2 = sigmoid(matmul(a1, w2));
    //auto loss = sum(-log(pow(activation, y) * pow(1 - activation, 1 - y) + 1e-6));
    auto lhs = y * log(a2 + 1e-16);
    auto rhs = (1 - y) * log(1 - a2 + 1e-16);
    auto add = lhs + rhs;
    //auto add = y * log(activation + 1e-16) + (1 - y) * log(1 - activation + 1e-16);
    auto neg_ones = constant(Matrix(sample_num, 1, -1));
    auto multi = multiply(neg_ones, add);
    auto loss = sum(multi);
    auto optimizer = gradient_descent_optimizer(loss, 0.1);
//    cout << "activation : " << activation.getNode() << endl;
//    cout << "add_lhs : " << lhs.getNode() << endl; 
//    cout << "add_rhs : " << rhs.getNode() << endl; 
//    cout << "add : " << add.getNode() << endl;
//    cout << "neg_ones : " << neg_ones.getNode() << endl;
//    cout << "multi : " << multi.getNode() << endl;
//    cout << "loss : " << loss.getNode() << endl;
    unordered_map<Node*, Matrix> map;
    Matrix x_mat = readDigitalCSV("/home/LiuYao/Documents/mytensorflow/test_data/x.csv");
    Matrix y_mat = readDigitalCSV("/home/LiuYao/Documents/mytensorflow/test_data/y.csv");
    map[x.getNode()] = x_mat;
    map[y.getNode()] = y_mat;
    Session sess;
    for(int i = 0; i < 100; i++){
        sess.run(optimizer, map);
        cout << "loss : " << sess.run(loss, map) << endl;
        cout << "a2 : " << sess.run(a2, map) << endl;
        cout << "================================================================================" << endl;
    }
}

void func(){
    Matrix m(2,2,1);
    cout << m;
    m = m + 2;
    cout << m;
}

int main()
{
    logistic_regression_v2_test();
    return 0;
}
